package my.springboot.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
import my.springboot.domain.primary.FormSet;
import my.springboot.mapper.FormSetMapper;
import my.springboot.po.vo.WechetTemplateVo;
import my.springboot.service.WechatService;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.net.URI;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import static my.springboot.common.Constant.CODE2SESSION_URL;
import static my.springboot.common.Constant.WECHAT_PUSH_MESSAGE_ACCESS_TOKEN;

@Service
@Slf4j
public class WechatServiceImpl implements WechatService {

    @Value("${system.resource.wx-app-id}")
    private String appId;
    @Value("${system.resource.wx-app-secret}")
    private String appSecret;
    @Value("${system.resource.wx-message-token-url}")
    private String messageTokenUrl;
    @Value("${system.resource.wx-message-push-url}")
    private String messagePushUrl;
    @Value("${system.resource.wx-code-url}")
    private String codeUrl;
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    @Autowired
    private FormSetMapper formSetMapper;

    @Override
    public JSONObject getWechatSession(String code) {
        if (StringUtils.isNotBlank(code)) {
            URI uri;
            try {
                uri = new URIBuilder(CODE2SESSION_URL)
                        .setParameter("appid", appId)
                        .setParameter("secret", appSecret)
                        .setParameter("js_code", code)
                        .setParameter("grant_type", "authorization_code")
                        .build();
                String result = get(uri);
                if (StringUtils.isNotBlank(result)) {
                    return JSONObject.parseObject(result);
                }
            } catch (Exception e) {
                log.error("通过code获取微信session错误：[{}]", e.getMessage());
            }
        }
        return null;
    }

    @Override
    public boolean sendMessage(String openId, String templateId, String page, String emphasisKeyword, Map<String, String> data) {
        if (StringUtils.isNoneBlank(openId) && StringUtils.isNoneBlank(templateId) && data != null) {
            FormSet formSet = formSetMapper.selectOne(new QueryWrapper<FormSet>().lambda().eq(FormSet::getOpenId, openId));
            if (formSet == null || StringUtils.isBlank(formSet.getFormId())) {
                log.info("微信推送:openId=[{}], templateId=[{}],没有可用的formId...", openId, templateId);
                return false;
            }
            String result = null;
            String accessToken = getWechatAccessToken();
            WechetTemplateVo vo = new WechetTemplateVo();
            vo.setData(data);
            vo.setTemplateId(templateId);
            vo.setTouser(openId);
            vo.setEmphasisKeyword(emphasisKeyword);
            vo.setFormId(formSet.getFormId());
            vo.setPage(page);
            JSONObject params = JSONObject.parseObject(JSONObject.toJSONString(vo));
            try {
                result = httpPostWithJSON(String.format(messagePushUrl, accessToken), params);
                log.info("微信推送:openId=[{}], templateId=[{}], 结果：[{}]", openId, templateId, result);
            } catch (Exception e) {
                log.error("微信推送:openId=[{}], templateId=[{}], 错误信息：[{}]", openId, templateId, e.getMessage());
            }
            JSONObject finalResult = JSONObject.parseObject(result);
            if (finalResult != null && StringUtils.equals("0", finalResult.getString("errcode"))) {
                formSet.setStatus(1);
                formSetMapper.updateById(formSet);
                return true;
            }
        }
        return false;
    }

    @Override
    public String getWechatAccessToken() {
        String result = null;
        String key = WECHAT_PUSH_MESSAGE_ACCESS_TOKEN;
        String accessToken = redisTemplate.opsForValue().get(key);
        if (StringUtils.isBlank(accessToken)) {
            try {
                URI uri = new URIBuilder(String.format(messageTokenUrl, appId, appSecret)).build();
                result = get(uri);
                log.info("获取微信[access_token]结果：[{}]", result);
            } catch (Exception e) {
                log.error("获取微信[access_token]错误：[{}]", e.getMessage());
            }
            if (StringUtils.isBlank(result)) {
                return null;
            }
            JSONObject jsonObject = JSONObject.parseObject(result);
            if (jsonObject == null) {
                return null;
            }
            accessToken = jsonObject.getString("access_token");
            if (StringUtils.isBlank(accessToken)) {
                return null;
            }
            redisTemplate.opsForValue().set(key, accessToken, 7200, TimeUnit.SECONDS);
        }
        return accessToken;
    }

    public static String get(URI uri) throws IOException {
        CloseableHttpClient httpClient = null;
        CloseableHttpResponse response = null;
        try {
            httpClient = HttpClients.createDefault();
            HttpGet httpGet = new HttpGet(uri);
            response = httpClient.execute(httpGet);
            if (response != null && response.getEntity() != null && response.getStatusLine().getStatusCode() == 200) {
                return EntityUtils.toString(response.getEntity(), "UTF-8");
            }
        } finally {
            if (httpClient != null) {
                httpClient.close();
            }
            if (response != null) {
                response.close();
            }
        }
        return "";
    }

    public static String httpPostWithJSON(String url, JSONObject jsonParam) throws Exception {
        HttpPost httpPost = new HttpPost(url);
        CloseableHttpClient client = HttpClients.createDefault();
        String respContent = null;
        StringEntity entity = new StringEntity(jsonParam.toString(), Consts.UTF_8.toString());
        entity.setContentEncoding(Consts.UTF_8.toString());
        entity.setContentType(ContentType.APPLICATION_JSON.getMimeType());
        httpPost.addHeader("Referer", "https://e.qq.com");
        CloseableHttpResponse res = null;
        try {
            res = client.execute(httpPost);
            if (res.getStatusLine().getStatusCode() == 200) {
                HttpEntity he = res.getEntity();
                respContent = EntityUtils.toString(he, Consts.UTF_8.toString());
            }
        } finally {
            client.close();
            res.close();
        }
        return respContent;
    }
}
